Modelo de Schelling

El tutorial de Agents.jl introduce el modelo de Schelling y lo vamos a reproducir acá.

using Agents

Paso 1 - Definir el espacio

size = (30, 30)
espacio = GridSpaceSingle(size; periodic=false, metric=:chebyshev)
GridSpaceSingle with size (30, 30), metric=chebyshev, periodic=false

Paso 2 - Definir los agentes

@agent struct Individuo(GridAgent{2})
    satisfecho::Bool
    grupo::Int
end
i0 = Individuo(id=0, pos=(1,1), satisfecho=false,grupo=1)
Individuo(0, (1, 1), false, 1)

Paso 3 - Definir las reglas de evolución

function vecinos_mismo_grupo(agente, modelo)
    vecinos_de_mismo_grupo = 0

    for vecino in nearby_agents(agente, modelo)
        if agente.grupo == vecino.grupo
            vecinos_de_mismo_grupo += 1
        end
    end
    vecinos_de_mismo_grupo
end

function schelling_step!(agente, modelo)
    tolerancia = modelo.tolerancia
    
    satisfecho(agente) = vecinos_mismo_grupo(agente, modelo)  tolerancia
    
    if  satisfecho(agente)# \ge y tab para hacer el simbolo de mayor o igual
        agente.satisfecho = true
    else
        es_distinto(a) = a.id != agente.id && !satisfecho(a)
        otro_agente = random_agent(modelo, es_distinto)
        swap_agents!(agente, otro_agente, modelo)

        agente.satisfecho = satisfecho(agente)
        otro_agente.satisfecho = satisfecho(agente)
    end

    return
end
schelling_step! (generic function with 1 method)

Paso 4 - Inicializar el modelo

using Random: Xoshiro
seed = 1234
rng = Xoshiro(seed)
Xoshiro(0x9951797c85a704f1, 0xb9d66be14dfba82b, 0xb170153285fd9556, 0xe90a07f7bdd1fd77, 0x9d4b5ee33e4bd661)
properties = Dict(:tolerancia => 3)
modelo = StandardABM(Individuo, espacio; properties, agent_step! =schelling_step!, rng)
StandardABM with 0 agents of type Individuo
 agents container: Dict
 space: GridSpaceSingle with size (30, 30), metric=chebyshev, periodic=false
 scheduler: fastest
 properties: tolerancia
ag0 = add_agent_single!(modelo; satisfecho=false, grupo=1)
ag1 = add_agent_single!(modelo; satisfecho=false, grupo=1)
Individuo(2, (15, 17), false, 1)
step!(modelo)
StandardABM with 2 agents of type Individuo
 agents container: Dict
 space: GridSpaceSingle with size (30, 30), metric=chebyshev, periodic=false
 scheduler: fastest
 properties: tolerancia

Crear funcion de inicializacion del sistema integrando todo lo anterior

function inicializar(; total_agentes=nothing, tamano_grilla=(30, 30), tolerancia=3, rng_seed=123, grilla_periodica=true)
    if isnothing(total_agentes)
        total_agentes = prod(tamano_grilla)::Int
    end

    space = GridSpaceSingle(tamano_grilla; periodic=grilla_periodica)
    properties = Dict(:tolerancia => tolerancia)
    rng = Xoshiro(rng_seed)
    modelo = StandardABM(
        Individuo, space;
        agent_step! = schelling_step!, properties, rng,
        container=Vector, # agents are not removed, so we us this
        scheduler=Schedulers.Randomly() # all agents are activated once at random
    )

    # Inicializo los agentes de manera aleatoria
    for n in 1:total_agentes
        add_agent_single!(modelo; satisfecho=false, grupo=n < total_agentes / 2 ? 1 : 2)
    end

    satisfecho(agente) = vecinos_mismo_grupo(agente,modelo)  modelo.tolerancia

    for ag in allagents(modelo)
        ag.satisfecho = satisfecho(ag)
    end

    return modelo

end

schelling = inicializar()
StandardABM with 900 agents of type Individuo
 agents container: Vector
 space: GridSpaceSingle with size (30, 30), metric=chebyshev, periodic=true
 scheduler: Agents.Schedulers.Randomly
 properties: tolerancia

Paso 5 - Evolucionar el sistema

step!(schelling)
StandardABM with 900 agents of type Individuo
 agents container: Vector
 space: GridSpaceSingle with size (30, 30), metric=chebyshev, periodic=true
 scheduler: Agents.Schedulers.Randomly
 properties: tolerancia
n_pasos = 3
step!(schelling, n_pasos)
StandardABM with 900 agents of type Individuo
 agents container: Vector
 space: GridSpaceSingle with size (30, 30), metric=chebyshev, periodic=true
 scheduler: Agents.Schedulers.Randomly
 properties: tolerancia
condicion_terminacion(modelo, tiempo) = tiempo <= 150
step!(schelling, condicion_terminacion)
StandardABM with 900 agents of type Individuo
 agents container: Vector
 space: GridSpaceSingle with size (30, 30), metric=chebyshev, periodic=true
 scheduler: Agents.Schedulers.Randomly
 properties: tolerancia

Paso 6 - Visualizar el sistema

# using CairoMakie
using WGLMakie
colorsatisfecho(agente) = (!agente.satisfecho ? :red
                         : agente.grupo == 1 ? :blue : :green)
colorgrupo(agente) = agente.grupo == 1 ? :red : :green
markergrupo(agente) = agente.grupo == 1 ? :circle : :rect
markergrupo (generic function with 1 method)
figure, _ = abmplot(schelling; agent_color = colorsatisfecho, agent_marker = markergrupo, as = 10)
figure # returning the figure displays it
┌ Warning: Found `resolution` in the theme when creating a `Scene`. The `resolution` keyword for `Scene`s and `Figure`s has been deprecated. Use `Figure(; size = ...` or `Scene(; size = ...)` instead, which better reflects that this is a unitless size and not a pixel resolution. The key could also come from `set_theme!` calls or related theming functions.
└ @ Makie C:\Users\augus\.julia\packages\Makie\ND0gA\src\scenes.jl:220
┌ Warning: Keywords `as, am, ac` has been deprecated in favor of
│           `agent_size, agent_marker, agent_color`
└ @ AgentsVisualizations C:\Users\augus\.julia\packages\Agents\EOn0z\ext\AgentsVisualizations\src\abmplot.jl:70

Para crear una visualizacion interactiva

# using GLMakie
figure, _ = abmplot(schelling; add_controls=true, agent_color = colorsatisfecho, agent_marker = markergrupo, as = 10)
figure # returning the figure displays it
┌ Warning: Found `resolution` in the theme when creating a `Scene`. The `resolution` keyword for `Scene`s and `Figure`s has been deprecated. Use `Figure(; size = ...` or `Scene(; size = ...)` instead, which better reflects that this is a unitless size and not a pixel resolution. The key could also come from `set_theme!` calls or related theming functions.
└ @ Makie C:\Users\augus\.julia\packages\Makie\ND0gA\src\scenes.jl:220

Paso 7 - Colectar datos del sistema

adata = [:pos, :satisfecho, :grupo]

schelling = inicializar()
pasos = 5

# Colectamos datos de los agentes y del modelo/sistema
adf, mdf = run!(schelling, pasos; adata) 

adf[end-10:end, :] # display only the last few rows
11×5 DataFrame
Row time id pos satisfecho grupo
Int64 Int64 Tuple… Bool Int64
1 5 890 (17, 27) true 2
2 5 891 (26, 24) true 2
3 5 892 (30, 11) true 2
4 5 893 (19, 5) true 2
5 5 894 (27, 26) true 2
6 5 895 (9, 16) true 2
7 5 896 (4, 1) true 2
8 5 897 (27, 15) true 2
9 5 898 (16, 15) true 2
10 5 899 (12, 8) true 2
11 5 900 (2, 29) true 2